import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;

public class Month
{
	public Month()
	{
		isSingleSelection = true;
	    isNormalSelectionMode = true;
		Calendar calendar = Calendar.getInstance();
		month = calendar.get(Calendar.MONTH);
		year = calendar.get(Calendar.YEAR);
		setNumberDays();
		init(calendar);
	}
	public Month(Date date)
	{
		isSingleSelection = true;
	    isNormalSelectionMode = true;
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		month = calendar.get(Calendar.MONTH);
		year = calendar.get(Calendar.YEAR);
		setNumberDays();
		init(calendar);
	}
	public void setSingleSelection(boolean type)
	{
		isSingleSelection = type;
	}
	public void setNormalSelectionMode(boolean mode)
	{
		isNormalSelectionMode = mode;
	}
	public JPanel getPanel()
    {
        return monthPanel;
    }
	public Date[] getSelectedDays()
    {
		if(dateSelected.isEmpty())
			return null;
		Object[] stringList = dateSelected.toArray();
		Date[] dateList = new Date[stringList.length];
		DateFormat df = Resources.getDateFormat();
		for(int i = 0; i < stringList.length; i++)
			try{
				dateList[i] = df.parse(stringList[i].toString());
			}catch(ParseException e)
			{
				return null;
			}
		return dateList;
    }
	public void setDaysMarked(Date[] days_)
    {
		if(days_ == null)
			daysMarked = null;
		else
		{
	        daysMarked = new String[days_.length];
	        for(int i = 0; i < days_.length; i++)
	        	daysMarked[i] = Resources.getDateFormat(days_[i]);
		}
    }
	public void setSelectedDays(Date[] dates)
	{
		DateFormat df = Resources.getDateFormat();
		dateSelected.clear();
		for(int i = 0; i < dates.length; i++)
			dateSelected.add(df.format(dates[i]));
		update();
	}
	public void update()
	{
		if(isNormalSelectionMode)
		{
			String value;
			for(int i = 0; i < ROW_COUNT; i++)
	            for(int j = 0; j < COLUMN_COUNT; j++)
	            {
	                value = getValueAt(i,j);
	                dayCell[i][j].setText(value);
	                if(value.equals(""))
	                    dayCell[i][j].setEnabled(false);
	                else
	                {
	                	if(isSelectedDay(new Integer(value)))
	                	{
	                		dayCell[i][j].setSelected(true);
	                		dayCell[i][j].setBackground(SELECTED);
	                		selectedDay = dayCell[i][j]; 
	                	} else if(isDayMarked(new Integer(value)))
	                	{
	                		dayCell[i][j].setSelected(false);
	                		dayCell[i][j].setBackground(MARKED);
	                	}else
	                	{
	                		dayCell[i][j].setSelected(false);
	                		dayCell[i][j].setBackground(NO_SELECTED);
	                	}
	                	dayCell[i][j].setEnabled(true);
	                }
	            }
		}else
		{
			String value;
			for(int i = 0; i < ROW_COUNT; i++)
	            for(int j = 0; j < COLUMN_COUNT; j++)
	            {
	                value = getValueAt(i,j);
	                dayCell[i][j].setText(value);
	                if(value.equals(""))
	                    dayCell[i][j].setEnabled(false);
	                else
	                {
	                	if(isSelectedDay(new Integer(value)))
	                	{
	                		dayCell[i][j].setSelected(true);
	                		dayCell[i][j].setBackground(SELECTED);
	                		selectedDay = dayCell[i][j]; 
	                		dayCell[i][j].setEnabled(true);
	                	} else if(isDayMarked(new Integer(value)))
	                	{
	                		dayCell[i][j].setSelected(false);
	                		dayCell[i][j].setBackground(MARKED);
	                		dayCell[i][j].setEnabled(true);
	                	}else
	                	{
	                		dayCell[i][j].setSelected(false);
	                		dayCell[i][j].setBackground(NO_SELECTED);
	                		dayCell[i][j].setEnabled(false);
	                	}
	                }
	            }
		}
	}
	public void setPrevMonth()
    {
        month--;
        if(month < 0)
        {
            month = 11;
            year--;
        }
        setNumberDays();
        update();
    }
    public void setNextMonth()
    {
        month++;
        if(month > 11)
        {
            month = 0;
            year++;
        }
        setNumberDays();
        update();
    }
    public void setMonth(int month_)
    {
    	month = month_ % 12;
    	setNumberDays();
        update();
    }
    public void setPrevYear()
    {
        year--;
        setNumberDays();
        update();
    }
    public void setNextYear()
    {
        year++;
        setNumberDays();
        update();
    }
    public void setYear(int year_)
    {
    	year = year_;
    	setNumberDays();
        update();
    }
    public int getYear()
    {
        return year;
    }
    public int getMonth()
    {
    	return month;
    }
    public String getNameMonth()
    {
        return MONTH_STRING[month]; 
    }
    public String getNameMonth(int month_)
    {
        return MONTH_STRING[month_]; 
    }
	private void init(Calendar calendar)
	{
		daysMarked = null;
		dateSelected = new ArrayList<String>(5);
        dateSelected.add(Resources.getDateFormat(calendar.getTime()));
		dayCell = new JButton[ROW_COUNT][COLUMN_COUNT];
        monthPanel = new JPanel(new GridLayout(1,COLUMN_COUNT));
        Border etched = BorderFactory.createEtchedBorder();
        monthPanel.setBorder(etched);
        String value;
        Font font = Resources.getFont(Resources.FONT_TYPE.CALENDAR);
        ActionListener listener = getListener();
        for(int i = 0; i < ROW_COUNT; i++)
            for(int j = 0; j < COLUMN_COUNT; j++)
            {
                value = getValueAt(i,j);
                dayCell[i][j] = new JButton(value);
                dayCell[i][j].addActionListener(listener);
                dayCell[i][j].setFont(font);
                dayCell[i][j].setBackground(NO_SELECTED);
                dayCell[i][j].setFocusable(false);
                dayCell[i][j].setBorderPainted(false);
                if(value.equals(""))
                    dayCell[i][j].setEnabled(false);
                else
                {
                	if(isDayMarked(new Integer(value)))
                		dayCell[i][j].setBackground(MARKED);
                	if(isSelectedDay(new Integer(value)))
                	{
                		dayCell[i][j].setSelected(true);
                		dayCell[i][j].setBackground(SELECTED);
                		selectedDay = dayCell[i][j]; 
                	}
                    dayCell[i][j].setEnabled(true);
                }
            }
        for(int i = 0; i < COLUMN_COUNT; i++)
            monthPanel.add(getColumn(i));
	}
	private ActionListener getListener()
	{
		return new 
	        ActionListener()
	        {
	            public void actionPerformed(ActionEvent e)
	            {
	            	JButton day = (JButton)e.getSource();
	            	if(day.isSelected())
	                {
	            		day.setSelected(false);
	            		if(isDayMarked(new Integer(day.getText())))
	                		day.setBackground(MARKED);
	            		else
	            			day.setBackground(NO_SELECTED);
	            		if(isSingleSelection)
	            			dateSelected.remove(0);
	            		else
	            			dateSelected.remove(getDateString(year,month,new Integer(day.getText())));
	            		selectedDay = null;
	                } else
	                {
	                	day.setSelected(true);
	                	day.setBackground(SELECTED);
	                	if((selectedDay != null)&&(isSingleSelection))
	                	{
	                		selectedDay.setSelected(false);
	                		if(!selectedDay.getText().equals(""))
	                		{
	                			if(isDayMarked(new Integer(selectedDay.getText())))
	                				selectedDay.setBackground(MARKED);
	                			else
	                				selectedDay.setBackground(NO_SELECTED);
	                		}
                			dateSelected.remove(0);//getDateString(year,month,new Integer(selectedDay.getText())));
	                	}
	                	selectedDay = day;
	                	dateSelected.add(getDateString(year,month,new Integer(selectedDay.getText())));
	                }
	            }
	        };
	}
	private String getDateString( int y, int m, int d)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.set(y, m, d);
		return Resources.getDateFormat(calendar.getTime());
	}
	private JPanel getColumn(int dayWeek)
    {
        JPanel columnPanel = new JPanel(new GridLayout(ROW_COUNT+1,1));
        JLabel dayLabel = new JLabel(Resources.getString(getNameDay(dayWeek)));
        dayLabel.setFont(Resources.getFont(Resources.FONT_TYPE.CALENDAR));
        columnPanel.add(dayLabel);
        for(int i = 0; i < ROW_COUNT; i++)
            columnPanel.add(dayCell[i][dayWeek]);
        return columnPanel;
    }
	private String getValueAt(int rowIndex, int columnIndex) 
    {
        int position = rowIndex*7 + columnIndex;
        int firstDay = getDay(year, month, 1);
        if((firstDay <= position) && (position < (firstDay + days)))
            return ""+ new Integer(position - firstDay + 1) +"";
        else 
            return "";
    }
	private boolean isSelectedDay(int day)
    {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day);
        Date dateToComp = calendar.getTime(); 
        DateFormat df = Resources.getDateFormat();
        if(dateSelected.indexOf(df.format(dateToComp)) != -1)
        	return true;
        else
        	return false;
    }
	private boolean isDayMarked(int day)
    {
        if(daysMarked == null)
            return false;
        String dayString = getDateString( year, month, day);
        for(int i = 0; i < daysMarked.length; i++)
        {
            if(dayString.equals(daysMarked[i]))
                return true;
        }
        return false;
    }
	/*
     * Retorna el día de la semana correspondiente a la fecha suministrada.
     * 0 = Domingo
     * 1 = Lunes
     * etc. 
     */
	private int getDay(int year_, int month_, int day_)
    {
        int i = 0;
        if(isBissextileYear(year_))
            i = 1;
        return ( (year_-1) % 7 + ( (int)((year_-1)/4) - (3 * ( (int)((year_-1)/100) + 1) )/4) % 7 + M[i][month_] + day_ % 7 ) % 7;
    }
	private String getNameDay(int c) 
    { 
        return DAY_STRING[c]; 
    }
	private boolean isBissextileYear(int year)
    {
        if((year % 400) == 0)
           return true;
        else if((year % 100) == 0)
           return false;
        else if((year % 4) == 0)
           return true;
        else
           return false;
    }
	private void setNumberDays()
    {
        switch(month)
        {
            case Calendar.JANUARY:
                days = JANUARY_DAYS;
                break;
            case Calendar.FEBRUARY:
                if(isBissextileYear(year))
                    days = FEBRUARY_BISSEXTILE_DAYS;
                else
                    days = FEBRUARY_DAYS;
                break;
            case Calendar.MARCH:
                days = MARCH_DAYS;
                break;
            case Calendar.APRIL:
                days = APRIL_DAYS;
                break;
            case Calendar.MAY:
                days = MAY_DAYS;
                break;
            case Calendar.JUNE:
                days = JUNE_DAYS;
                break;
            case Calendar.JULY:
                days = JULY_DAYS;
                break;
            case Calendar.AUGUST:
                days = AUGUST_DAYS;
                break;
            case Calendar.SEPTEMBER:
                days = SEPTEMBER_DAYS;
                break;
            case Calendar.OCTOBER:
                days = OCTOBER_DAYS;
                break;
            case Calendar.NOVEMBER:
                days = NOVEMBER_DAYS;
                break;
            case Calendar.DECEMBER:
                days = DECEMBER_DAYS;
                break;
        }
    }
	private int year;
    private int month;
    private int days;
    private JPanel monthPanel;
    private JButton[][] dayCell;
    private JButton selectedDay;
    private ArrayList<String> dateSelected;
    private String[] daysMarked;
    private boolean isSingleSelection;
    private boolean isNormalSelectionMode;
	private static final String[] MONTH_STRING = 
    {
        "january","february","march","april","may","june","july","august","september","october","november","december"
    };
    private static final String[] DAY_STRING = 
    {
        "sunday","monday","tuesday","wednesday","thursday","friday","saturday"
    };
    //Module per Month
    private static final int[][] M = 
    {
        {0,3,3,6,1,4,6,2,5,0,3,5},//regular
        {0,3,4,0,2,5,0,3,6,1,4,6}//bissextile
    };
	private static final int JANUARY_DAYS = 31;
    private static final int FEBRUARY_DAYS = 28;
    private static final int FEBRUARY_BISSEXTILE_DAYS = 29;
    private static final int MARCH_DAYS = 31;
    private static final int APRIL_DAYS = 30;
    private static final int MAY_DAYS = 31;
    private static final int JUNE_DAYS = 30;
    private static final int JULY_DAYS = 31;
    private static final int AUGUST_DAYS = 31;
    private static final int SEPTEMBER_DAYS = 30;
    private static final int OCTOBER_DAYS = 31;
    private static final int NOVEMBER_DAYS = 30;
    private static final int DECEMBER_DAYS = 31;
    private static final int ROW_COUNT = 6;
    private static final int COLUMN_COUNT = 7;
    private static final Color NO_SELECTED = Color.WHITE;
    private static final Color SELECTED = Color.RED;
    private static final Color MARKED = Color.GREEN;
}